﻿#include <QDomDocument>
#include <QTextBlock>
#include <QFileInfo>
#include <Configuration.h>
#include <Resources.h>
#include <Constants.h>
#include <Utils.h>
#include "XMLCoreEditor.h"
#include "TextEditorWidget.h"
#include "NodeEditorWidget.h"
#include "GraphicsEditorWidget.h"
#include "PreviewWidget.h"

namespace Domy {

XMLCoreEditor::XMLCoreEditor(QWidget *parent)
    : QTabWidget(parent),
      m_text_editor(new TextEditorWidget(this)),
      m_node_editor(new NodeEditorWidget(this)),
      m_graphics_editor(new GraphicsEditorWidget(this)),
      m_preview_widget(new PreviewWidget(this)),
      m_is_changed(false)
{
    this->setTabPosition(QTabWidget::West);

    this->tabBar()->setIconSize(QSize(24, 24));

    for (int index = 0; index < EditorCounts; ++index) {
        createEditor(index);
    }

    connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotOnCurrentEditorIndexChanged(int)));
    connect(m_text_editor, SIGNAL(signalReload()), this, SLOT(slotOnReload()));
}

XMLCoreEditor::~XMLCoreEditor()
{

}

QByteArray XMLCoreEditor::getPlainText() const
{
    return m_text_editor->getEditor()->toPlainText().toUtf8();
}

QString XMLCoreEditor::getLineText(int line) const
{
    return m_text_editor->getEditor()->document()->findBlockByLineNumber(line).text();
}

bool XMLCoreEditor::openFile(const QString &file_path)
{
    bool rslt = false;

    do {
        if (file_path.isEmpty()) {
            rslt = true;
            break;
        }

        QFile file(file_path);

        if (!file.open(QIODevice::ReadOnly)) {
            break;
        }
        QByteArray content = file.readAll();

        QString codec_name = m_text_editor->getEditor()->getCodecName();

        QString content_text = Utils::unicodeDecode(content, codec_name);

        m_text_editor->getEditor()->appendPlainText(content_text);
        m_text_editor->getEditor()->document()->setModified(false);
        // 光标移动到文档首部
        m_text_editor->getEditor()->setTextCursor(QTextCursor(m_text_editor->getEditor()->document()));
        // 重置一下undo、redo
        m_text_editor->getEditor()->setUndoRedoEnabled(false);
        m_text_editor->getEditor()->setUndoRedoEnabled(true);

        m_file_path = file_path;

        file.close();

        rslt = true;
    } while (0);

    connect(m_text_editor->getEditor(), SIGNAL(modificationChanged(bool)), this, SLOT(slotOnContentModificationChanged(bool)));
    connect(m_text_editor->getEditor(), SIGNAL(textChanged()), this, SIGNAL(signalContentTextChanged()));
    connect(m_text_editor->getEditor(), SIGNAL(redoAvailable(bool)), this, SIGNAL(signalRedoAvailable(bool)));
    connect(m_text_editor->getEditor(), SIGNAL(undoAvailable(bool)), this, SIGNAL(signalUndoAvailable(bool)));

    return true;
}

void XMLCoreEditor::setFilePath(const QString &file_path)
{
    m_file_path = file_path;

    emit signalFilePathChanged();
}

QString XMLCoreEditor::getFilePath() const
{
    return m_file_path;
}

QString XMLCoreEditor::getFileName() const
{
    QFileInfo fi(m_file_path);
    QString file_name;
    if (fi.exists()) {
        file_name = fi.fileName();
    }
    return file_name;
}

bool XMLCoreEditor::save(QString * const error)
{
    bool rslt = this->save(m_file_path, error);
    if (rslt) {
        m_is_changed = false;
        m_text_editor->getEditor()->document()->setModified(false);
    }
    return rslt;
}

bool XMLCoreEditor::saveAs(const QString &file_path, QString * const error)
{
    return this->save(file_path, error);
}

bool XMLCoreEditor::isChanged() const
{
    return m_is_changed;
}

void XMLCoreEditor::setErrorLineHighlight(int line)
{
    m_text_editor->getEditor()->setErrorLineHighlight(line);
}

void XMLCoreEditor::clearErrorLineHighlight()
{
    m_text_editor->getEditor()->clearErrorLineHighlight();
}

bool XMLCoreEditor::isUndoEnable() const
{
    return m_text_editor->getEditor()->document()->availableUndoSteps() > 0;
}

bool XMLCoreEditor::isRedoEnable() const
{
    return m_text_editor->getEditor()->document()->availableRedoSteps() > 0;
}

void XMLCoreEditor::doEditAction(ActionKey key)
{
    AbstractEditorWidget *editor_widget =
            dynamic_cast<AbstractEditorWidget *>(this->currentWidget());

    if (editor_widget) {
        editor_widget->triggerAction(key);
    }
}

void XMLCoreEditor::updateSettings()
{
    m_text_editor->getEditor()->updateSettings();
}

void XMLCoreEditor::slotOnCurrentEditorIndexChanged(int index)
{

}

void XMLCoreEditor::slotOnContentModificationChanged(bool is_changed)
{
    m_is_changed = is_changed;

    emit signalContentModificationChanged();
}

void XMLCoreEditor::slotOnReload()
{
    disconnect(m_text_editor->getEditor(), SIGNAL(modificationChanged(bool)), this, SLOT(slotOnContentModificationChanged(bool)));
    disconnect(m_text_editor->getEditor(), SIGNAL(textChanged()), this, SIGNAL(signalContentTextChanged()));
    disconnect(m_text_editor->getEditor(), SIGNAL(redoAvailable(bool)), this, SIGNAL(signalRedoAvailable(bool)));
    disconnect(m_text_editor->getEditor(), SIGNAL(undoAvailable(bool)), this, SIGNAL(signalUndoAvailable(bool)));

    m_text_editor->getEditor()->clear();

    openFile(m_file_path);
}

void XMLCoreEditor::createEditor(int index)
{
    QWidget *widget = Q_NULLPTR;
    QString name, icon_name;

    switch (index) {
    case EditorIndex_Text:
        widget = m_text_editor;
        name = tr("Text Editor");
        icon_name = "text_editor";
        break;
    case EditorIndex_Node:
        widget = m_node_editor;
        name = tr("Node Editor");
        icon_name = "node_editor";
        break;
    case EditorIndex_Graphics:
        widget = m_graphics_editor;
        name = tr("Graphics Editor");
        icon_name = "graphics_editor";
        break;
    case EditorIndex_Preview:
        widget = m_preview_widget;
        name = tr("Preview");
        icon_name = "preview";
        break;
    default:
        return;
    }

    this->addTab(widget, "");
    this->setTabIcon(index, GET_ICON(icon_name));
    this->setTabToolTip(index, name);
}

bool XMLCoreEditor::save(const QString &file_path, QString * const error)
{
    QFile file(file_path);
    QString err;
    bool rslt = false;
    do {
        if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
            err = tr("The file(\"%1\") opened unsuccessfully !").arg(file_path);
            break;
        }

        QString content = m_text_editor->getEditor()->toPlainText();

        // 转换编码
        QByteArray data = Utils::unicodeEncode(content, m_text_editor->getEditor()->getCodecName());

        if (file.write(data) != data.length()) {
            err = tr("The file(\"%1\") wrote error !").arg(file_path);
            break;
        }

        rslt = true;

    } while (0);

    if (error) {
        *error = err;
    }

    return rslt;
}

} // namespace Domy
